home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 September / PCWorld_2008-09_cd.bin / v cisle / sadanastroju / lightning-0.8-tb-win.xpi / chrome / calendar.jar / content / calendar / mouseoverPreviews.js < prev    next >
Text File  |  2008-02-05  |  16KB  |  496 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is OEone Calendar Code, released October 31st, 2001.
  15.  *
  16.  * The Initial Developer of the Original Code is
  17.  * OEone Corporation.
  18.  * Portions created by the Initial Developer are Copyright (C) 2001
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s): Garth Smedley <garths@oeone.com>
  22.  *                 Mike Potter <mikep@oeone.com>
  23.  *                 Chris Charabaruk <coldacid@meldstar.com>
  24.  *                 Colin Phillips <colinp@oeone.com>
  25.  *                 Karl Guertin <grayrest@grayrest.com>
  26.  *                 Mike Norton <xor@ivwnet.com>
  27.  *                 ArentJan Banck <ajbanck@planet.nl>
  28.  *                 Eric Belhaire <belhaire@ief.u-psud.fr>
  29.  *                 Philipp Kewisch <mozilla@kewis.ch>
  30.  *
  31.  * Alternatively, the contents of this file may be used under the terms of
  32.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  33.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  34.  * in which case the provisions of the GPL or the LGPL are applicable instead
  35.  * of those above. If you wish to allow use of your version of this file only
  36.  * under the terms of either the GPL or the LGPL, and not to allow others to
  37.  * use your version of this file under the terms of the MPL, indicate your
  38.  * decision by deleting the provisions above and replace them with the notice
  39.  * and other provisions required by the GPL or the LGPL. If you do not delete
  40.  * the provisions above, a recipient may use your version of this file under
  41.  * the terms of any one of the MPL, the GPL or the LGPL.
  42.  *
  43.  * ***** END LICENSE BLOCK ***** */
  44.  
  45. /**
  46.  * Code which generates event and task (todo) preview tooltips/titletips
  47.  *  when the mouse hovers over either the event list, the task list, or
  48.  *  an event or task box in one of the grid views.
  49.  *
  50.  *   (Portions of this code were previously in calendar.js and unifinder.js,
  51.  *   some of it duplicated.)
  52.  */
  53.  
  54. /** PUBLIC
  55.  *
  56.  *  This changes the mouseover preview based on the start and end dates
  57.  *  of an occurrence of a (one-time or recurring) calEvent or calToDo.
  58.  *  Used by all grid views.
  59.  */
  60.  
  61. function onMouseOverItem( occurrenceBoxMouseEvent )
  62. {
  63.   if ("occurrence" in occurrenceBoxMouseEvent.currentTarget) {
  64.     // occurrence of repeating event or todo
  65.     var occurrence = occurrenceBoxMouseEvent.currentTarget.occurrence;
  66.  
  67.     const toolTip = document.getElementById("itemTooltip");
  68.  
  69.     var holderBox;
  70.     if (isEvent(occurrence)) {
  71.       holderBox = getPreviewForEvent(occurrence, occurrence.startDate, occurrence.endDate);
  72.     } else if (isToDo(occurrence)) {
  73.       holderBox = getPreviewForTask(occurrence);
  74.     }
  75.     if (holderBox) {
  76.       setToolTipContent(toolTip, holderBox);
  77.       return true;
  78.     } 
  79.   }
  80.   return false;
  81. }
  82.  
  83. /** For all instances of an event, as displayed by unifinder. **/
  84. function onMouseOverEventTree( toolTip, mouseEvent )
  85. {
  86.   var item = unifinderTreeView.getItemFromEvent(mouseEvent);
  87.   if (isEvent(item)) {
  88.     var holderBox = getPreviewForEvent(item);
  89.     if (holderBox) {
  90.       setToolTipContent(toolTip, holderBox);
  91.       return true;
  92.     } 
  93.   }
  94.   return false;
  95. }
  96.  
  97. /** For all instances of a task, as displayed by unifinderToDo. **/
  98. function onMouseOverTaskTree( toolTip, mouseEvent )
  99. {
  100.   var item = getToDoFromEvent( mouseEvent );
  101.   if (isToDo(item)) {
  102.     var holderBox = getPreviewForTask(item);
  103.     if (holderBox) {
  104.       setToolTipContent(toolTip, holderBox);
  105.       return true;
  106.     }
  107.   }
  108.   return false;
  109. }
  110.  
  111. /**
  112.  * Removes old content from tooltip, adds new content box to tooltip,
  113.  * then resizes the tooltip to the size of the new content box.
  114.  *
  115.  * @param tooltip       The tooltip to modify.
  116.  * @param holderBox     The box element containing the new content.
  117.  */
  118. function setToolTipContent(toolTip, holderBox)
  119. {
  120.   while (toolTip.hasChildNodes()) {
  121.     toolTip.removeChild( toolTip.firstChild );
  122.   }
  123.  
  124.   // workaround bug 369225 (aspect: tooltip may not shrink height)
  125.   toolTip.sizeTo(0, 0);
  126.  
  127.   toolTip.appendChild( holderBox );
  128.   var width = holderBox.boxObject.width;
  129.   var height = holderBox.boxObject.height;
  130.  
  131.   // workaround bug 369225 (aspect: tooltip height too short)
  132.   // Add top and bottom border and padding to workaround bug where bottom
  133.   // tooltip border disappears if wrapped description below header grid.
  134.   height += 1 + 2 + 2 + 1;
  135.  
  136.   toolTip.sizeTo(width, height);
  137. }
  138.  
  139. /**
  140.  *  Called when a user hovers over a todo element and the text for the mouse over is changed.
  141.  */
  142.  
  143. function getPreviewForTask( toDoItem )
  144. {
  145.   if( toDoItem )
  146.   {
  147.     const vbox = document.createElement( "vbox" );
  148.     vbox.setAttribute("class", "tooltipBox");
  149.     // tooltip appears above or below pointer, so may have as little as
  150.     // one half the screen height available (avoid top going off screen).
  151.     vbox.maxHeight = Math.floor(screen.height / 2);
  152.     boxInitializeHeaderGrid(vbox);
  153.  
  154.     var hasHeader = false;
  155.          
  156.     if (toDoItem.title)
  157.     {
  158.       boxAppendLabeledText(vbox, "tooltipTitle", toDoItem.title);
  159.       hasHeader = true;
  160.     }
  161.  
  162.     var location = toDoItem.getProperty("LOCATION");
  163.     if (location)
  164.     {
  165.       boxAppendLabeledText(vbox, "tooltipLocation", location);
  166.       hasHeader = true;
  167.     }
  168.    
  169.     if (toDoItem.entryDate && toDoItem.entryDate.isValid)
  170.     {
  171.       boxAppendLabeledDateTime(vbox, "tooltipStart", toDoItem.entryDate);
  172.       hasHeader = true;
  173.     }
  174.    
  175.     if (toDoItem.dueDate && toDoItem.dueDate.isValid)
  176.     {
  177.       boxAppendLabeledDateTime(vbox, "tooltipDue", toDoItem.dueDate);
  178.       hasHeader = true;
  179.     }   
  180.  
  181.     if (toDoItem.priority && toDoItem.priority != 0)
  182.     {
  183.       var priorityInteger = parseInt(toDoItem.priority);
  184.       var priorityString;
  185.  
  186.       // These cut-offs should match calendar-event-dialog.js
  187.       if (priorityInteger >= 1 && priorityInteger <= 4) {
  188.            priorityString = calGetString('calendar', 'highPriority'); // high priority
  189.       } else if (priorityInteger == 5) {
  190.           priorityString = calGetString('calendar', 'mediumPriority'); // medium priority
  191.       } else {
  192.           priorityString = calGetString('calendar', 'lowPriority'); // low priority
  193.       }
  194.       boxAppendLabeledText(vbox, "tooltipPriority", priorityString);
  195.       hasHeader = true;
  196.     }
  197.  
  198.     if (toDoItem.status && toDoItem.status != "NONE")
  199.     {
  200.       var status = getToDoStatusString(toDoItem);
  201.       boxAppendLabeledText(vbox, "tooltipStatus", status);
  202.       hasHeader = true;
  203.     }
  204.  
  205.     if (toDoItem.percentComplete != 0 && toDoItem.percentComplete != 100)
  206.     {
  207.       boxAppendLabeledText(vbox, "tooltipPercent", String(toDoItem.percentComplete)+"%");
  208.       hasHeader = true;
  209.     } else if (toDoItem.percentComplete == 100)
  210.     {
  211.       if (toDoItem.completedDate == null) {
  212.         boxAppendLabeledText(vbox, "tooltipPercent", "100%");
  213.       } else { 
  214.         boxAppendLabeledDateTime(vbox, "tooltipCompleted", toDoItem.completedDate);
  215.       } 
  216.       hasHeader = true;
  217.     }
  218.  
  219.     var description = toDoItem.getProperty("DESCRIPTION");
  220.     if (description)
  221.     {
  222.       // display wrapped description lines like body of message below headers
  223.       if (hasHeader) {
  224.         boxAppendBodySeparator(vbox);
  225.       }
  226.       boxAppendBody(vbox, description);
  227.     }
  228.  
  229.     return ( vbox );
  230.   } 
  231.   else
  232.   {
  233.     return null;
  234.   }
  235. }
  236.  
  237. /**
  238.  *  Called when mouse moves over a different, or
  239.  *  when mouse moves over event in event list.
  240.  *  The instStartDate is date of instance displayed at event box
  241.  *  (recurring or multiday events may be displayed by more than one event box
  242.  *  for different days), or null if should compute next instance from now.
  243.  */
  244. function getPreviewForEvent( event, instStartDate, instEndDate )
  245. {
  246.   const vbox = document.createElement( "vbox" );
  247.   vbox.setAttribute("class", "tooltipBox");
  248.   // tooltip appears above or below pointer, so may have as little as
  249.   // one half the screen height available (avoid top going off screen).
  250.   vbox.maxHeight = Math.floor(screen.height / 2);
  251.   boxInitializeHeaderGrid(vbox);
  252.  
  253.   if (event)
  254.   {
  255.     if (event.title)
  256.     {
  257.       boxAppendLabeledText(vbox, "tooltipTitle", event.title);
  258.     }
  259.  
  260.     var location = event.getProperty("LOCATION");
  261.     if (location)
  262.     {
  263.       boxAppendLabeledText(vbox, "tooltipLocation", location);
  264.     }
  265.  
  266.     if (event.startDate || instStartDate)
  267.     {
  268.       var startDate, endDate;
  269.       if (instStartDate && instEndDate) {
  270.         startDate = instStartDate;
  271.         endDate = instEndDate;
  272.       } else {
  273.         // Event may be recurrent event.   If no displayed instance specified,
  274.         // use next instance, or previous instance if no next instance.
  275.         var occ = getCurrentNextOrPreviousRecurrence(event);
  276.         startDate = instStartDate || occ.startDate;
  277.         endDate = occ.endDate;
  278.       }
  279.       boxAppendLabeledDateTimeInterval(vbox, "tooltipDate", startDate, endDate);
  280.     }
  281.  
  282.     if (event.status && event.status != "NONE")
  283.     {
  284.       var statusString = getEventStatusString(event);
  285.       boxAppendLabeledText(vbox, "tooltipStatus", statusString);
  286.     }
  287.  
  288.     var description = event.getProperty("DESCRIPTION");
  289.     if (description)
  290.     {
  291.       boxAppendBodySeparator(vbox);
  292.       // display wrapped description lines, like body of message below headers
  293.       boxAppendBody(vbox, description);
  294.     }
  295.  
  296.     return ( vbox );
  297.   }
  298.   else
  299.   {
  300.     return null;
  301.   }
  302. }
  303.  
  304.  
  305. /** String for event status: (none), Tentative, Confirmed, or Cancelled **/
  306. function getEventStatusString(calendarEvent)
  307. {
  308.   switch( calendarEvent.status )
  309.   {
  310.     // Event status value keywords are specified in RFC2445sec4.8.1.11
  311.     case "TENTATIVE":
  312.       return calGetString('calendar', "statusTentative");
  313.     case "CONFIRMED":
  314.       return calGetString('calendar', "statusConfirmed");
  315.     case "CANCELLED":
  316.       return calGetString('calendar', "statusCancelled");
  317.      default: 
  318.         return "";
  319.   }
  320. }
  321.  
  322. /** String for todo status: (none), NeedsAction, InProcess, Cancelled, or Completed **/
  323. function getToDoStatusString(iCalToDo)
  324. {
  325.   switch( iCalToDo.status )
  326.   {
  327.     // Todo status keywords are specified in RFC2445sec4.8.1.11
  328.     case "NEEDS-ACTION":
  329.       return calGetString('calendar', "statusNeedsAction");
  330.     case "IN-PROCESS":
  331.       return calGetString('calendar', "statusInProcess");
  332.     case "CANCELLED":
  333.       return calGetString('calendar', "statusCancelled");
  334.     case "COMPLETED":
  335.       return calGetString('calendar', "statusCompleted");
  336.      default: 
  337.         return "";
  338.   }
  339. }
  340.  
  341. /**
  342.  * PRIVATE: Append a separator, a thin space between header and body.
  343.  *
  344.  * @param vbox      box to which to append separator.
  345.  */
  346. function boxAppendBodySeparator(vbox) {
  347.   const separator = document.createElement("separator");
  348.   separator.setAttribute("class", "tooltipBodySeparator");
  349.   vbox.appendChild(separator);
  350. }
  351.  
  352. /**
  353.  * PRIVATE: Append description to box for body text.  Text may contain
  354.  * paragraphs; line indent and line breaks will be preserved by CSS.
  355.  * @param box           box to which to append body
  356.  * @param textString    text of body
  357.  */
  358. function boxAppendBody(box, textString)
  359. {
  360.   var textNode = document.createTextNode(textString);
  361.   var xulDescription = document.createElement("description");
  362.   xulDescription.setAttribute("class", "tooltipBody");
  363.   xulDescription.appendChild(textNode);
  364.   box.appendChild(xulDescription);
  365. }
  366.  
  367. /**
  368.  * PRIVATE: Use dateFormatter to format date and time,
  369.  * and to header grid append a row containing localized Label: date.
  370.  */
  371. function boxAppendLabeledDateTime(box, labelProperty, date)
  372. {
  373.   var dateFormatter = Components.classes["@mozilla.org/calendar/datetime-formatter;1"]
  374.                                 .getService(Components.interfaces.calIDateTimeFormatter);
  375.   date = date.getInTimezone(calendarDefaultTimezone());
  376.   var formattedDateTime = dateFormatter.formatDateTime(date);
  377.   boxAppendLabeledText(box, labelProperty, formattedDateTime);
  378. }
  379.  
  380. /**
  381.  * PRIVATE: Use dateFormatter to format date and time interval,
  382.  * and to header grid append a row containing localized Label: interval.
  383.  * @param box               contains header grid.
  384.  * @param labelProperty     name of property for localized field label.
  385.  * @param start             calDateTime of start of time interval.
  386.  * @param end               calDateTime of end of time interval.
  387.  */
  388. function boxAppendLabeledDateTimeInterval(box, labelProperty, start, end)
  389. {
  390.   var dateFormatter = Components.classes["@mozilla.org/calendar/datetime-formatter;1"]
  391.                                 .getService(Components.interfaces.calIDateTimeFormatter);
  392.   var startString = new Object();
  393.   var endString = new Object();
  394.   start = start.getInTimezone(calendarDefaultTimezone());
  395.   end = end.getInTimezone(calendarDefaultTimezone());
  396.   dateFormatter.formatInterval(start, end, startString, endString);
  397.   if (endString.value != "") {
  398.     boxAppendLabeledText(box, labelProperty, startString.value + ' - ' + endString.value);
  399.   } else {
  400.     boxAppendLabeledText(box, labelProperty, startString.value);
  401.   }
  402. }
  403.  
  404. /**
  405.  * PRIVATE: create empty 2-column grid for header fields,
  406.  * and append it to box.
  407.  */
  408. function boxInitializeHeaderGrid(box)
  409. {
  410.   var grid = document.createElement("grid");
  411.   grid.setAttribute("class", "tooltipHeaderGrid");
  412.   var rows;
  413.   {
  414.     var columns = document.createElement("columns");
  415.     {
  416.       var labelColumn = document.createElement("column");
  417.       labelColumn.setAttribute("class", "tooltipLabelColumn");
  418.       columns.appendChild(labelColumn);
  419.       var valueColumn = document.createElement("column");
  420.       valueColumn.setAttribute("class", "tooltipValueColumn");
  421.       columns.appendChild(valueColumn);
  422.     }
  423.     grid.appendChild(columns);
  424.     rows = document.createElement("rows");
  425.     grid.appendChild(rows);
  426.   }
  427.   box.appendChild(grid);
  428. }
  429.  
  430. /**
  431.  * PRIVATE: To headers grid, append a row containing Label: value,
  432.  * where label is localized text for labelProperty.
  433.  * @param box               box containing headers grid
  434.  * @param labelProperty     name of property for localized name of header
  435.  * @param textString        value of header field.
  436.  */
  437. function boxAppendLabeledText(box, labelProperty, textString)
  438. {
  439.   var labelText = calGetString('calendar', labelProperty);
  440.   var rows = box.getElementsByTagName("rows")[0];
  441.   { 
  442.     var row = document.createElement("row");
  443.     {
  444.       row.appendChild(createTooltipHeaderLabel(labelText));
  445.       row.appendChild(createTooltipHeaderDescription(textString));
  446.     }
  447.     rows.appendChild(row);
  448.   }
  449. }
  450.  
  451. /** PRIVATE: create element for field label (for header grid). **/
  452. function createTooltipHeaderLabel(text)
  453. {
  454.   var label = document.createElement("label");
  455.   label.setAttribute("class", "tooltipHeaderLabel");
  456.   label.appendChild(document.createTextNode(text));
  457.   return label;
  458. }
  459.  
  460. /** PRIVATE: create element for field value (for header grid). **/
  461. function createTooltipHeaderDescription(text)
  462. {
  463.   var label = document.createElement("description");
  464.   label.setAttribute("class", "tooltipHeaderDescription");
  465.   label.appendChild(document.createTextNode(text));
  466.   return label;
  467. }
  468.  
  469. /**
  470.  * If now is during an occurrence, return the occurrence.
  471.  * Else if now is before an occurrence, return the next occurrence.
  472.  * Otherwise return the previous occurrence.
  473.  */
  474. function getCurrentNextOrPreviousRecurrence(calendarEvent)
  475. {
  476.     if (!calendarEvent.recurrenceInfo) {
  477.         return calendarEvent;
  478.     }
  479.  
  480.     var dur = calendarEvent.duration.clone();
  481.     dur.isNegative = true;
  482.  
  483.     // To find current event when now is during event, look for occurrence
  484.     // starting duration ago.
  485.     var probeTime = now();
  486.     probeTime.addDuration(dur);
  487.  
  488.     var occ = calendarEvent.recurrenceInfo.getNextOccurrence(probeTime);
  489.  
  490.     if (!occ) {
  491.         var occs = calendarEvent.recurrenceInfo.getOccurrences(calendarEvent.startDate, probeTime, 0, {});
  492.         occ = occs[occs.length -1];
  493.     }
  494.     return occ;
  495. }
  496.